package icasue.stronger.wareable.logicstronger.logicsupport;

import icasue.stronger.wareable.logicstronger.StrongerAdvice;
import org.springframework.lang.Nullable;
import icasue.reflect.handles.fields.FieldOF;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @Author: Qiao Hang
 * @CreateDate: 2021/11/9 下午4:26
 * @UpdateDate:
 * @Description:
 */
public class AutoSqlStrongerLogic extends StrongerAdvice {

    private static ThreadLocal<Annotation> metadataStore;
    private static Class<? extends Annotation> AutoProviderMetadata;

    static {
        try {
            AutoProviderMetadata = (Class<? extends Annotation>)
                    Class.forName("icasue.tools.sqlhelper.adaptor.annotation.AutoProviderMetadata");
            metadataStore = (ThreadLocal<Annotation>) FieldOF.get_ofTp_fName_instance_.apply(
                    Class.forName("icasue.tools.sqlhelper.adaptor.ibatis.ReflectionSqlProvider"),
                    "metadataStore",
                    null
            );
        }catch (Throwable e){
            throw new RuntimeException("Support logic for 'AutoSqlStrongerLogic.class' depend on model 'icasue-tools-sqlhelper'.");
        }
    }

    public AutoSqlStrongerLogic() {
        super();
        addBeforeMethodLogic(beforeLogic);
        addAfterMethodLogic(afterLogic);
    }

    private StrongerAdvice.BeforeMethodLogic beforeLogic = (Class<?> proxyClass, Object invoker,
                                                            Method method, Object... params) -> {
        Annotation metadata = method.getAnnotation(AutoProviderMetadata);
        if(metadata == null){
            metadata = proxyClass.getAnnotation(AutoProviderMetadata);
        }
        if(metadata != null){
            metadataStore.set(metadata);
        }
        return null;
    };

    private StrongerAdvice.AfterMethodLogic afterLogic = (@Nullable Object result,
                                                          Class<?> proxyClass, Object invoker,
                                                          Method method, Object... params) -> {
        metadataStore.remove();
        return result;
    };

}